#!/usr/bin/env python
# -*- coding: utf-8 -*-

from math import log
import time
import threading
from common.config import ServiceConfig
from common.utils import LogUtil
import consul
from web_server.models import service_info
from web_server.models.service_info import ServiceInfo

logger = LogUtil.get_logger(__name__)

class PollService:
    """设备服务发现服务"""
    
    def __init__(self, stop_cb: callable):
        self.__del_services_cb = None
        self.__old_services_cb = None
        self.__new_services_cb = None
        self.__stop_cb = stop_cb
        self.__service_info_map = {}
        self.__stop_flag = threading.Event()
        self.__consul_client = None
        self.__poll_thread = None

        consul_host = ServiceConfig.CONSUL_HOST
        consul_port = ServiceConfig.CONSUL_PORT
        self.__consul_client = consul.Consul(host=consul_host, port=consul_port)
        self.__poll_thread = threading.Thread(target=self.__poll_services, daemon=True)
    
    def __poll_services(self):
        while not self.__stop_flag.is_set():
            try:
                # 非阻塞查询可用服务实例
                _, current_services = self.__consul_client.health.service(ServiceConfig.DEVICE_SERVICE_NAME, passing=True)
                
                # 获取当前服务ID列表
                current_service_ids = set()
                for service in current_services:
                    service_info = service['Service']
                    current_service_ids.add(service_info['ID'])
                # logger.debug(f"当前服务: {current_service_ids}")

                # 获取已有服务ID列表
                existing_service_ids = set(self.__service_info_map.keys())
                # logger.debug(f"已有服务: {existing_service_ids}")
                
                del_service_ids = existing_service_ids - current_service_ids
                old_service_ids = existing_service_ids & current_service_ids
                new_service_ids = current_service_ids - existing_service_ids

                # 移除离线服务
                if del_service_ids:
                    self.__handle_del_services(del_service_ids)

                # 检查现存服务
                if old_service_ids:
                    self.__handle_old_services(old_service_ids)
                    
                # # 添加新增服务
                if new_service_ids:
                    self.__handle_new_services(current_services, new_service_ids)

                time.sleep(ServiceConfig.POLL_SLEEP_TIME)
            except Exception as e:
                # critical error, exit
                logger.critical(f"设备服务发现服务异常: {e}")
                if not self.__stop_flag.is_set():
                    self.__stop_flag.set()
                    if self.__stop_cb:
                        self.__stop_cb('poll')

    def __handle_del_services(self, del_service_ids):
        """处理移除服务"""
        for service_id in del_service_ids:
            logger.debug(f"服务下线: {service_id}")
            service_info = self.__service_info_map.pop(service_id, None)
            if service_info:
                if self.__del_services_cb is not None:
                    self.__del_services_cb(service_info)
                else:
                    logger.warning("未注册服务下线回调")

    def __handle_old_services(self, old_service_ids):
        """处理旧服务"""
        for service_id in old_service_ids:
            # logger.debug(f"服务在线: {service_id}")
            service_info = self.__service_info_map.get(service_id)
            if service_info:
                if self.__old_services_cb is not None:
                    self.__old_services_cb(service_info)
                else:
                    logger.warning("未注册服务在线回调")

    def __handle_new_services(self, current_services, new_service_ids):
        """处理新增服务"""
        for service in current_services:
            service_id = service['Service']['ID']
            if service_id in new_service_ids:
                logger.debug(f"服务上线: {service_id}")
                tags = service['Service']['Tags']
                service_info = ServiceInfo(service_id)
                for tag in tags:
                    if tag.startswith('host='):
                        service_info.host = tag.split('=')[1]
                    elif tag.startswith('rep_port='):
                        service_info.rep_port = int(tag.split('=')[1])
                    elif tag.startswith('pub_port='):
                        service_info.pub_port = int(tag.split('=')[1])
                    elif tag.startswith('res_port='):
                        service_info.res_port = int(tag.split('=')[1])
                    elif tag.startswith('aio_port='):
                        service_info.aio_port = int(tag.split('=')[1])
                    elif tag.startswith('timestamp='):
                        service_info.timestamp = int(tag.split('=')[1])
                logger.debug(f"服务地址: {service_info.host}")
                logger.debug(f"应答端口: {service_info.rep_port}")
                logger.debug(f"发布端口: {service_info.pub_port}")
                logger.debug(f"资源端口: {service_info.res_port}")
                logger.debug(f"异步端口: {service_info.aio_port}")
                self.__service_info_map[service_id] = service_info
                if self.__new_services_cb is not None:
                    self.__new_services_cb(service_info)
                else:
                    logger.warning("未注册服务上线回调")

    def __del__(self):
        self.destroy()

    def destroy(self):
        if not self.__stop_flag.is_set():
            self.__stop_flag.set()
            if self.__stop_cb:
                self.__stop_cb('poll')
        if self.__poll_thread:
            self.__poll_thread.join()
            self.__poll_thread = None
        self.__consul_client = None
        self.__service_info_map.clear()
        self.__stop_cb = None
        self.__new_services_cb = None
        self.__old_services_cb = None
        self.__del_services_cb = None

    def start(self):
        self.__poll_thread.start()
        return self.__poll_thread and self.__poll_thread.is_alive()

    def set_del_services_cb(self, cb: callable):
        self.__del_services_cb = cb

    def set_old_services_cb(self, cb: callable):
        self.__old_services_cb = cb

    def set_new_services_cb(self, cb: callable):
        self.__new_services_cb = cb

    